﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Drawing;

namespace Fractals
{
    class JuliaSetGenerator
    {
        const int m_maxIterations = 150;
        const double m_maxValueExtent = 2.0;
        const double m_maxNorm = m_maxValueExtent * m_maxValueExtent;

        public static void GenerateJuliaSetImage(Bitmap bitmap, Complex c)
        {
            double scale = 2 * m_maxValueExtent / Math.Min(bitmap.Width, bitmap.Height);
            for (int y = 0; y < bitmap.Height; y++)
            {
                double imaginary = (bitmap.Height / 2 - y) * scale;

                for (int x = 0; x < bitmap.Width; x++)
                {
                    double real = (x - bitmap.Width / 2) * scale;
                    double color = CalcJuliaSetColor(new Complex(real, imaginary), c);

                    bitmap.SetPixel(x, y, GetColor(color));
                }
            }
        }

        private static double CalcJuliaSetColor(Complex z, Complex c)
        {
            int iteration = 0;

            do
            {
                z = z * z + c;
                iteration++;
            } while ((z.Real * z.Real + z.Imaginary * z.Imaginary) < m_maxNorm && iteration < m_maxIterations);

            if (iteration < m_maxIterations)
                return (double)iteration / m_maxIterations;
            else
                return 0; // black
        }

        /// <summary>
        /// transfer function method for coloring the output
        /// </summary>
        /// <param name="value">ranges from 0 to 1</param>
        /// <returns>the color</returns>
        private static Color GetColor(double value)
        {
            const double MaxColor = 256;
            const double ContrastValue = 0.2;

            return Color.FromArgb((int)(MaxColor * Math.Pow(value, ContrastValue)), (int)(MaxColor * Math.Pow(value, ContrastValue)), 0);
        }

    }
}
